﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using GiveGraphMappers.ContextBalancer;
using GiveGraphModel;

namespace GiveGraphMappers
{
    public abstract class AbstractGiveGraphMapper<T> where T : class 
    {

        private readonly Type _dbsetType;
        
        protected AbstractGiveGraphMapper()
        {
            _dbsetType = typeof(T);
        }


        public void ForceSave()
        {
            Call(ctx => ctx.SaveChanges());
        }

        protected static TU Call<TU>(Func<GiveGraphContext, TU> method)
        {

            GiveGraphContext ctx = null;
            try
            {
                ctx = GiveGraphContextBalancer.Balancer.Get();
                return method(ctx);
            }
            finally
            {
                if (ctx != null)
                    GiveGraphContextBalancer.Balancer.Put(ctx);
            }
        }

        public T Get(int id)
        {
            return Call((ctx) => DoGet(ctx, id));

        }

        

        public int Size()
        {
            return Call(DoSize);
        }

        public int Add(T t)
        {
            return Call(ctx => DoAdd(ctx, t));
        }

        public bool Delete(T t)
        {
            return Call(ctx => DoDelete(t,ctx));
        }

        public IEnumerable<T> GetAll()
        {
            return Call(DoGetAll);
        }

        public bool Update(T t)
        {
            return Call(ctx => DoUpdate(ctx, t));
        }

        public T CreateInstance()
        {
            return Call(DoCreateInstance);
        }

        protected  T DoGet(GiveGraphContext ctx, int id)
        {
            return ctx.Set<T>().Find(id);
        }


        protected int DoAdd(GiveGraphContext ctx, T elem)
        {
            ctx.Set<T>().Add(elem);
            ctx.SaveChanges();
            return GetElementKey(elem);

        }

        protected bool DoUpdate(GiveGraphContext ctx, T elem)
        {
            if (ctx.Entry(elem).State == EntityState.Detached)
                ctx.Set<T>().Add(elem);

            ctx.SaveChanges();
            return true;
        }

        protected  int DoSize(GiveGraphContext ctx)
        {
            return ctx.Set<T>().Count();
        }

        protected bool DoDelete(T t, GiveGraphContext ctx)
        {
            ctx.Set<T>().Remove(t);
            ctx.SaveChanges();
            return true;
        }

        protected IEnumerable<T> DoGetAll(GiveGraphContext ctx)
        {
            return ctx.Set<T>();
        }

        protected T DoCreateInstance(GiveGraphContext ctx)
        {
            return ctx.Set<T>().Create();
        }

        protected abstract int GetElementKey(T t);

        public T Attach(T t)
        {
            return Call((ctx) => DoAttach(ctx, t));
        }

        protected T DoAttach(GiveGraphContext ctx, T t)
        {
            return ctx.Set<T>().Attach(t);
        }

        public GiveGraphContext GetContext()
        {
            return Call(ctx => ctx);
        }
    }
}
